﻿///<copyright>
/// Copyright © 2009 Stephen Styrchak. All Rights Reserved.
///</copyright>
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System.Reflection;

namespace Ferpect.ComponentModel.Design
{
    public partial class ColorPickerControl : UserControl
    {
        private Dictionary<TextBox, string> beforeEdit;
        private Color unmultipliedColor;
        private string beforeEditComboValue;

        public ColorPickerControl()
        {
            InitializeComponent();
            this.beforeEdit = new Dictionary<TextBox, string>();

            this.comboBox1.Items.AddRange(GetNamedColors());
        }

        private object[] GetNamedColors()
        {
            var fields = typeof(Color).GetProperties(BindingFlags.Static | BindingFlags.Public);
            string[] names = new string[fields.Length];
            for (int i = 0; i < names.Length; ++i)
            {
                names[i] = fields[i].Name;
            }
            Array.Sort(names);
            return names;
        }

        public Color Value
        {
            get
            {
                return this.colorSwatch.GetColor();
            }
            set
            {
                float invA = 255f / (float)value.A;
                this.unmultipliedColor.R = (byte)MathHelper.Clamp((float)Math.Round(invA * (float)value.R), 0f, 255f);
                this.unmultipliedColor.G = (byte)MathHelper.Clamp((float)Math.Round(invA * (float)value.G), 0f, 255f);
                this.unmultipliedColor.B = (byte)MathHelper.Clamp((float)Math.Round(invA * (float)value.B), 0f, 255f);
                this.unmultipliedColor.A = (byte)value.A;

#if DEBUG
                Color preAlpha = this.unmultipliedColor;
                preAlpha.A = 255;
                float alpha = ((float)this.unmultipliedColor.A) / 255f;
                Color testPremultiplied = Color.Multiply(preAlpha, alpha);
#endif

                this.colorSwatch.R = value.R;
                this.colorSwatch.G = value.G;
                this.colorSwatch.B = value.B;
                this.colorSwatch.A = value.A;

                this.OnLoad(EventArgs.Empty);
            }
        }

        private void OnLoad(object sender, EventArgs e)
        {
            this.redSlider.Value = this.unmultipliedColor.R;
            this.greenSlider.Value = this.unmultipliedColor.G;
            this.blueSlider.Value = this.unmultipliedColor.B;
            this.alphaSlider.Value = this.unmultipliedColor.A;

            this.redTextBox.Text = this.unmultipliedColor.R.ToString();
            this.greenTextBox.Text = this.unmultipliedColor.G.ToString();
            this.blueTextBox.Text = this.unmultipliedColor.B.ToString();
            this.alphaTextBox.Text = this.unmultipliedColor.A.ToString();

            this.premultipliedLabel.Text = this.colorSwatch.ToString();
        }

        private void OnSliderScroll(object sender, EventArgs e)
        {
            TrackBar t = sender as TrackBar;
            if (t == this.redSlider)
            {
                this.unmultipliedColor.R = (byte)t.Value;
                this.redTextBox.Text = t.Value.ToString();
            }
            else if (t == this.greenSlider)
            {
                this.unmultipliedColor.G = (byte)t.Value;
                this.greenTextBox.Text = t.Value.ToString();
            }
            else if (t == this.blueSlider)
            {
                this.unmultipliedColor.B = (byte)t.Value;
                this.blueTextBox.Text = t.Value.ToString();
            }
            else if (t == this.alphaSlider)
            {
                this.unmultipliedColor.A = (byte)t.Value;
                this.alphaTextBox.Text = t.Value.ToString();
            }
            SetColorSwatch();
            this.comboBox1.Text = String.Empty;
        }

        private void OnEnterTextBox(object sender, EventArgs e)
        {
            TextBox textBox = (TextBox)sender;
            this.beforeEdit[textBox] = textBox.Text;
        }

        private void OnLeaveTextBox(object sender, EventArgs e)
        {
            TextBox textBox = (TextBox)sender;
            byte newValue;
            if (Byte.TryParse(textBox.Text, out newValue))
            {
                if (textBox == this.redTextBox)
                {
                    this.unmultipliedColor.R = newValue;
                    this.redSlider.Value = newValue;
                }
                else if (textBox == this.greenTextBox)
                {
                    this.unmultipliedColor.G = newValue;
                    this.greenSlider.Value = newValue;
                }
                else if (textBox == this.blueTextBox)
                {
                    this.unmultipliedColor.B = newValue;
                    this.blueSlider.Value = newValue;
                }
                else if (textBox == this.alphaTextBox)
                {
                    this.unmultipliedColor.A = newValue;
                    this.alphaSlider.Value = newValue;
                }
                SetColorSwatch();
                this.comboBox1.Text = String.Empty;
            }
            else
            {
                textBox.Text = this.beforeEdit[textBox];
            }
        }

        private void SetColorSwatch()
        {
            Color preAlpha = this.unmultipliedColor;
            preAlpha.A = 255;
            float alpha = ((float)this.unmultipliedColor.A) / 255f;
            Color premultiplied = Color.Multiply(preAlpha, alpha);
            this.colorSwatch.R = premultiplied.R;
            this.colorSwatch.G = premultiplied.G;
            this.colorSwatch.B = premultiplied.B;
            this.colorSwatch.A = premultiplied.A;
            this.premultipliedLabel.Text = this.colorSwatch.ToString();
        }

        private void OnKeyDownTextBox(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                this.OnLeaveTextBox(sender, e);
                this.OnEnterTextBox(sender, e);
            }
            else if (e.KeyCode == Keys.Escape)
            {
                TextBox textBox = (TextBox)sender;
                textBox.Text = this.beforeEdit[textBox];
            }
        }

        private void OnEnterComboBox(object sender, EventArgs e)
        {
            this.beforeEditComboValue = ((ComboBox)sender).SelectedValue as string;
        }

        private void OnNamedColorSelectionChanged(object sender, EventArgs e)
        {
            var colorBox = (ComboBox)sender;
            string value = (string)colorBox.Text;
            if (!String.IsNullOrEmpty(value))
            {
                var property = typeof(Color).GetProperty(value, BindingFlags.Static | BindingFlags.Public);
                this.Value = (Color)property.GetValue(null, null);
            }
        }
    }
}
